package ace.module.account.core.impl.service.authentication.handler.impl.wxminiapp;

import ace.cmp.core.exception.BusinessException;
import ace.cmp.json.api.JsonService;
import ace.module.account.api.enums.IamAccountPassportPassportTypeEnum;
import ace.module.account.api.model.auth.AuthenticationGrantType;
import ace.module.account.api.model.auth.dto.AuthenticationResult;
import ace.module.account.api.model.auth.input.GenericAuthenticationInputImpl;
import ace.module.account.api.model.auth.input.params.AuthenticationParamsWxMpPhoneCode;
import ace.module.account.core.impl.dao.entity.IamAccountPassport;
import ace.module.account.core.impl.manager.IamAccountPassportManager;
import ace.module.account.core.impl.manager.cache.IamAuthenticationLoginCacheManager;
import ace.module.account.core.impl.service.authentication.handler.RegisterQuickManager;
import ace.module.account.core.impl.service.authentication.handler.impl.AbstractAuthenticationHandler;
import ace.module.account.core.impl.service.authentication.handler.model.input.AuthenticationHandlerContextInput;
import ace.module.weixin.api.WxsMiniAppApi;
import ace.module.weixin.api.model.dto.WxsGetPhoneNumberResultDto;
import ace.module.weixin.api.model.dto.WxsPhoneInfoDto;
import java.util.HashMap;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

/**
 * @author caspar
 * @date 2023/3/16 9:49 微信小程序Login phone认证
 * @see <a href="https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html">微信小程序Login code认证</a>
 */
@Slf4j
@Component
public class WxMiniAppLoginPhoneAuthenticationHandler
    extends AbstractAuthenticationHandler<
        AuthenticationParamsWxMpPhoneCode,
        GenericAuthenticationInputImpl<AuthenticationParamsWxMpPhoneCode>> {

  private final WxsMiniAppApi wxsMiniAppApi;
  private final IamAccountPassportManager iamAccountPassportManager;
  private final IamAuthenticationLoginCacheManager iamAuthenticationLoginCacheManager;
  private final RegisterQuickManager registerQuickManager;

  protected WxMiniAppLoginPhoneAuthenticationHandler(
      JsonService jsonService,
      WxsMiniAppApi wxsMiniAppApi,
      IamAccountPassportManager iamAccountPassportManager,
      IamAuthenticationLoginCacheManager iamAuthenticationLoginCacheManager,
      RegisterQuickManager registerQuickManager) {
    super(AuthenticationGrantType.WX_MINI_PHONE_AUTH.getCode(), jsonService);
    this.wxsMiniAppApi = wxsMiniAppApi;
    this.iamAccountPassportManager = iamAccountPassportManager;
    this.iamAuthenticationLoginCacheManager = iamAuthenticationLoginCacheManager;
    this.registerQuickManager = registerQuickManager;
  }

  @Override
  protected AuthenticationResult doAuthentication(
      AuthenticationHandlerContextInput<AuthenticationParamsWxMpPhoneCode> context) {
    Long iamAppId = context.getAuthenticationContext().getIamApplication().getId();
    String wxMiniAppId = context.getAuthenticationContext().getBizParams().getWxMiniAppId();
    String code = context.getAuthenticationContext().getBizParams().getCode();
    String tag = context.getAuthenticationContext().getTag();
    boolean registerQuickFlag =
        Boolean.TRUE.equals(
            context.getAuthenticationContext().getBizParams().getRegisterQuickFlag());
    WxsGetPhoneNumberResultDto wxsGetPhoneNumberResultDTO =
        this.wxsMiniAppApi.getPhoneNumberByPhoneNumberCode(wxMiniAppId, code).check();
    String purePhoneNumber =
        Optional.ofNullable(wxsGetPhoneNumberResultDTO)
            .map(WxsGetPhoneNumberResultDto::getPhoneInfo)
            .map(WxsPhoneInfoDto::getPurePhoneNumber)
            .orElse(null);
    if (StringUtils.isBlank(purePhoneNumber)) {
      log.info("account_auth_fail,{}", wxsGetPhoneNumberResultDTO);
      throw new BusinessException("认证失败");
    }

    IamAccountPassport accountPassport =
        this.iamAccountPassportManager.getByIamAppIdAndTagAndPassportAndPassportType(
            iamAppId,
            tag,
            purePhoneNumber,
            IamAccountPassportPassportTypeEnum.PHONE.getCode());
    // 生成支持快速注册sessionkey与保存
    registerQuickManager.ifSupportRegisterQuickThenAndThrow(
        accountPassport != null,
        registerQuickFlag,
        (sessionKey) -> {
          iamAuthenticationLoginCacheManager.setWxsGetPhoneNumberResultDto(
              sessionKey, wxsGetPhoneNumberResultDTO);
        });
    if (accountPassport == null) {
      throw new BusinessException("认证失败");
    }

    Long accountId = accountPassport.getIamAccountId();

    return AuthenticationResult.builder().accountId(accountId).attributes(new HashMap<>()).build();
  }
}
